/* ------------------------------------------------------------------------*
 *
 * ------------------------------------------------------------------------*/
#define _GD25Q_HAL_MODEL_
 
#include "gd25q_hal.h"
#include "gd25q_cmd.h"
#include "gd32f10x_rcc.h"
#include "gd32f10x_gpio.h"
#include "gd32f10x_spi.h"
#include "gd32f10x_dma.h"

/*****************************************************************************//*!
* @brief   Dma for spi rx handle.
*               
* @param   none
*
* @return  none
*
* @ Pass/ Fail criteria: none
*****************************************************************************/  
void DMA1_Channel2_IRQHandler()
{
	DMA_Enable(DMA1_CHANNEL3, DISABLE);	
	DMA_Enable(DMA1_CHANNEL2, DISABLE);	 
	
	GDSPI->CTLR2 &= ~ (SPI_CTLR2_DMARE | SPI_CTLR2_DMATE);
	
	gd25qDmaEndSt = DMA1->IFR &(DMA_IFR_TCIF2 | DMA_IFR_TCIF3 | DMA_IFR_ERRIF2 | DMA_IFR_ERRIF3);
	
	DMA1->ICR = DMA_ICR_GIC3 | DMA_ICR_TCIC3 | DMA_ICR_HTIC3 | DMA_ICR_ERRIC3;              
	DMA1->ICR = DMA_ICR_GIC2 | DMA_ICR_TCIC2 | DMA_ICR_HTIC2 | DMA_ICR_ERRIC2;
	
	//add code to tell os that data rw finished ----------------------------------------------
	
	//----------------------------------------------------------------------------------------
}

/*****************************************************************************//*!
* @brief   Dma for spi tx handle.
*               
* @param   none
*
* @return  none
*
* @ Pass/ Fail criteria: none
*****************************************************************************/  
void DMA1_Channel3_IRQHandler()
{

}

/*****************************************************************************//*!
* @brief   hal init.
*               
* @param   none
*
* @return  none
*
* @ Pass/ Fail criteria: none
*****************************************************************************/    
void gdSpiInit()
{
    
    SPI_InitPara SpiPar;
    DMA_InitPara DMA_InitStructure;
	// Configure the GPIO ports 
    GPIO_InitPara  GPIO_InitStructure;

    // Enable USART APB clock 
    RCC_APB2PeriphClock_Enable(RCC_APB2PERIPH_SPI1, ENABLE);
    RCC_APB2PeriphReset_Enable(RCC_APB2PERIPH_SPI1, ENABLE);
    RCC_APB2PeriphReset_Enable(RCC_APB2PERIPH_SPI1, DISABLE);   

    // Configure USART Rx/Tx as alternate function push-pull 
    GPIO_InitStructure.GPIO_Pin = GPIO_PIN_4;              //HOLD
    GPIO_InitStructure.GPIO_Mode = GPIO_MODE_OUT_PP;
    GPIO_InitStructure.GPIO_Speed = GPIO_SPEED_50MHZ;
    GPIO_Init(GPIOA,&GPIO_InitStructure);
    GPIO_InitStructure.GPIO_Pin = GPIO_PIN_0 | GPIO_PIN_1; //WP CS
    GPIO_InitStructure.GPIO_Mode = GPIO_MODE_OUT_PP;
    GPIO_InitStructure.GPIO_Speed = GPIO_SPEED_50MHZ;
    GPIO_Init(GPIOB,&GPIO_InitStructure);
    GPIO_InitStructure.GPIO_Pin = GPIO_PIN_5 | GPIO_PIN_7; //SCK MOSI
    GPIO_InitStructure.GPIO_Mode = GPIO_MODE_AF_PP;
    GPIO_InitStructure.GPIO_Speed = GPIO_SPEED_50MHZ;
    GPIO_Init(GPIOA,&GPIO_InitStructure);
    GPIO_InitStructure.GPIO_Pin = GPIO_PIN_6;              //MISO
    GPIO_InitStructure.GPIO_Mode = GPIO_MODE_IN_FLOATING;
    GPIO_InitStructure.GPIO_Speed = GPIO_SPEED_50MHZ;
    GPIO_Init(GPIOA,&GPIO_InitStructure);
    GD25Cs(1);
    GD25Hold(1);
    GD25WpDis();
    
    //config spi
    SpiPar.SPI_TransType = SPI_TRANSTYPE_FULLDUPLEX;
    SpiPar.SPI_Mode = SPI_MODE_MASTER;
    SpiPar.SPI_FrameFormat = SPI_FRAMEFORMAT_8BIT;
    SpiPar.SPI_SCKPL = SPI_SCKPL_HIGH;
    SpiPar.SPI_SCKPH = SPI_SCKPH_2EDGE;
    SpiPar.SPI_SWNSSEN = SPI_SWNSS_SOFT;
    SpiPar.SPI_PSC = SPI_PSC_16;
    SpiPar.SPI_FirstBit = SPI_FIRSTBIT_MSB;
    SpiPar.SPI_CRCPOL = 0x07;
    
    SPI_Init(GDSPI, &SpiPar);
    SPI_Enable(GDSPI, ENABLE);
    
    NVIC_SetPriority(SPI1_IRQn, 0xFF);
	NVIC_ClearPendingIRQ(SPI1_IRQn);
	NVIC_DisableIRQ(SPI1_IRQn);
    
    //DMA config For Rx----------------------------------------------------------------------------------
    DMA_DeInit(DMA1_CHANNEL2);                                                    //For spi1-rx
    DMA_InitStructure.DMA_DIR = DMA_DIR_PERIPHERALSRC;                            //Peripheral to memory
    DMA_InitStructure.DMA_PeripheralInc = DMA_PERIPHERALINC_DISABLE;              //peripheral address inc disable
    DMA_InitStructure.DMA_MemoryInc = DMA_MEMORYINC_ENABLE;                       //peripheral address inc enable  
    DMA_InitStructure.DMA_MemoryDataSize = DMA_MEMORYDATASIZE_BYTE;               //Memory data size -- byte
    DMA_InitStructure.DMA_PeripheralDataSize = DMA_PERIPHERALDATASIZE_BYTE;       //peripheral data size -- byte
    DMA_InitStructure.DMA_Mode = DMA_MODE_NORMAL;                                 //cycle mode disable(DMA_MODE_NORMAL) / enable(DMA_MODE_NORMAL)
    DMA_InitStructure.DMA_Priority = DMA_PRIORITY_HIGH;                           //priority
    DMA_InitStructure.DMA_MTOM = DMA_MEMTOMEM_DISABLE;                            //mem to mem disable               //init
    DMA_InitStructure.DMA_PeripheralBaseAddr = (uint32_t)(&(GDSPI->DTR));          //Peripheral data address

    DMA_InitStructure.DMA_BufferSize = 1;                                        //buffer size
    DMA_InitStructure.DMA_MemoryBaseAddr = (uint32_t)(&(GDSPI->DTR));              //Memory data address
    DMA_Init(DMA1_CHANNEL2, &DMA_InitStructure);  
    // Enable DMA1 channel2
	DMA1->ICR = DMA_ICR_GIC2 | DMA_ICR_TCIC2 | DMA_ICR_HTIC2 | DMA_ICR_ERRIC2;
    DMA_Enable(DMA1_CHANNEL2, DISABLE);	                                          //enable dma
    
    DMA_INTConfig(DMA1_CHANNEL2, DMA_INT_TC, ENABLE);
    NVIC_SetPriority(DMA1_Channel2_IRQn, 0xFF);
	NVIC_ClearPendingIRQ(DMA1_Channel2_IRQn);
	NVIC_EnableIRQ(DMA1_Channel2_IRQn);
    
    //DMA config For Tx----------------------------------------------------------------------------------
    DMA_DeInit(DMA1_CHANNEL3);                                                    //For spi1-rx
    DMA_InitStructure.DMA_DIR = DMA_DIR_PERIPHERALDST;                            //Peripheral to memory
    DMA_InitStructure.DMA_PeripheralInc = DMA_PERIPHERALINC_DISABLE;              //peripheral address inc disable
    DMA_InitStructure.DMA_MemoryInc = DMA_MEMORYINC_ENABLE;                       //peripheral address inc enable  
    DMA_InitStructure.DMA_MemoryDataSize = DMA_MEMORYDATASIZE_BYTE;               //Memory data size -- byte
    DMA_InitStructure.DMA_PeripheralDataSize = DMA_PERIPHERALDATASIZE_BYTE;       //peripheral data size -- byte
    DMA_InitStructure.DMA_Mode = DMA_MODE_NORMAL;                                 //cycle mode disable(DMA_MODE_NORMAL) / enable(DMA_MODE_NORMAL)
    DMA_InitStructure.DMA_Priority = DMA_PRIORITY_HIGH;                           //priority
    DMA_InitStructure.DMA_MTOM = DMA_MEMTOMEM_DISABLE;                            //mem to mem disable               //init
    DMA_InitStructure.DMA_PeripheralBaseAddr = (uint32_t)(&(GDSPI->DTR));         //Peripheral data address
    
    DMA_InitStructure.DMA_BufferSize = 1;                                         //buffer size
    DMA_InitStructure.DMA_MemoryBaseAddr = (uint32_t)(&(GDSPI->DTR));             //Memory data address
    DMA_Init(DMA1_CHANNEL3, &DMA_InitStructure);  
    // Enable DMA1 channel2
	DMA1->ICR = DMA_ICR_GIC3 | DMA_ICR_TCIC3 | DMA_ICR_HTIC3 | DMA_ICR_ERRIC3;
    DMA_Enable(DMA1_CHANNEL3, DISABLE);	                                          //enable dma
    NVIC_SetPriority(DMA1_Channel3_IRQn, 0xFF);
	NVIC_ClearPendingIRQ(DMA1_Channel3_IRQn);
	NVIC_EnableIRQ(DMA1_Channel3_IRQn);

}

/*****************************************************************************//*!
* @brief   DMA control.
*               
* @param   none
*
* @return  none
*
* @ Pass/ Fail criteria: none
*****************************************************************************/ 
void gdSpiDmaRw(uint8_t ModeRW, uint32_t  Len, uint8_t *Data)
{
	uint8_t DataFixed;
	
	gd25qDmaEndSt = 0;
	
	//DMA channel disable
	DMA_Enable(DMA1_CHANNEL2, DISABLE);	 
	DMA_Enable(DMA1_CHANNEL3, DISABLE);	 

	//clear dma flag
	DMA1->ICR = DMA_ICR_GIC3 | DMA_ICR_TCIC3 | DMA_ICR_HTIC3 | DMA_ICR_ERRIC3 |             
				DMA_ICR_GIC2 | DMA_ICR_TCIC2 | DMA_ICR_HTIC2 | DMA_ICR_ERRIC2;
		
	//set length
	DMA1_CHANNEL2->RCNT = Len;
	DMA1_CHANNEL3->RCNT = Len;
	
	//set address of data
	if(GD25Q_READ == ModeRW)
	{
		//readmode
		DMA1_CHANNEL2->CTLR |= DMA_CTLR_MNAGA;                 //rx med address inc
		DMA1_CHANNEL3->CTLR &= ~DMA_CTLR_MNAGA;                //tx mem address fixed
		DMA1_CHANNEL2->MBAR = (uint32_t)(Data);                //rx med address inc
		DMA1_CHANNEL3->MBAR = (uint32_t)(&DataFixed);          //tx mem address fixed
	}
	else
	{
		//writemode
		DMA1_CHANNEL3->CTLR |= DMA_CTLR_MNAGA;                 //tx med address inc
		DMA1_CHANNEL2->CTLR &= ~DMA_CTLR_MNAGA;                //rx mem address fixed
		DMA1_CHANNEL3->MBAR = (uint32_t)(Data);                //tx med address inc
		DMA1_CHANNEL2->MBAR = (uint32_t)(&DataFixed);          //rx mem address fixed
	}
	
	//DMA channel enable
	DMA_Enable(DMA1_CHANNEL3, ENABLE);	
	DMA_Enable(DMA1_CHANNEL2, ENABLE);	                                   
	
	//DMA req enable
	GDSPI->CTLR2 |= SPI_CTLR2_DMARE | SPI_CTLR2_DMATE;
	
	//delete these code if a OS be used-------------------------------------------------------
	while(!(gd25qDmaEndSt & (DMA_IFR_TCIF2 | DMA_IFR_TCIF3 | DMA_IFR_ERRIF2 | DMA_IFR_ERRIF3)) ){}
	if(gd25qDmaEndSt &(DMA_IFR_ERRIF2 | DMA_IFR_ERRIF3) )
	{
		
	}
	else
	{
	
	}
	
	//add code to wait dma finish //for os----------------------------------------------------
	
	//----------------------------------------------------------------------------------------
	
}



/*****************************************************************************//*!
* @brief   spi data read and write.
*               
* @param   none
*
* @return  none
*
* @ Pass/ Fail criteria: none
*****************************************************************************/ 
uint8_t dgSpiRw(uint8_t dataW)
{
    uint8_t dataR;
    
    while(!(GDSPI->STR & SPI_STR_TBE)){}             //wait tx idle
        
    if(GDSPI->STR & SPI_STR_RBNE)
        dataR = GDSPI->DTR;
    
    GDSPI->DTR = dataW;
    dataW = 0;
    while(!(GDSPI->STR & SPI_STR_RBNE)){}            //wait tx idle
    dataR = (uint8_t) GDSPI->DTR;
    return ( dataR );
}
